#include "TimerQueue.h"
#include <time.h>

namespace chaos
{
	std::vector<byte> TimerQueue::s_ids(INIT_ID_SIZE);

	std::atomic<uint32> TimerQueue::s_curTimers(0);

	Mutex TimerQueue::s_mutex;


	TimerQueue::TimerQueue(EventCentre* pCentre) :
		m_pCentre(pCentre),
		m_lastRunTime(0)
	{
	}


	TimerQueue::~TimerQueue()
	{
	}


	void TimerQueue::Launch(EventList& activeEvents)
	{
		m_lastRunTime = GetCurrentMSec();

		while (!m_timerQueue.Empty())
		{
			const TimerSharedPtr& timer = m_timerQueue.Front();
			assert(timer);

			if (m_lastRunTime < timer->NextRunTime())
				break;

			m_timerQueue.Pop();

			if (timer->IsSuspend())
			{
				//暂停的定时器如果不是循环的就直接删除
				if (timer->Repeat())
				{
					timer->ToNextRunTime();
					m_timerQueue.Push(timer);
				}
				else
				{
					DelTimer(timer);
				}
				continue;
			}

			activeEvents.push_back(timer);

			//循环定时任务
			if (timer->Repeat())
			{
				timer->ToNextRunTime();
				m_timerQueue.Push(timer);
			}
		}
	}
		

	uint32 TimerQueue::AddTimer(const TimerSharedPtr& timer)
	{
		if (!timer)
			return -1;

		const EventKey& key = timer->GetEvKey();

		int id = key.timerId;

		if (m_timerMap.find(id) != m_timerMap.end())
			return -1;

		m_timerMap.insert(std::make_pair(id, timer));
		
		m_timerQueue.Push(timer);

		++s_curTimers;

		m_pCentre->WakeUp();

		return 0;

	}


	uint32 TimerQueue::DelTimer(const TimerSharedPtr& timer)
	{
		if (!timer)
			return -1;
			
		m_timerMap.erase(timer->GetEvKey().timerId);

		--s_curTimers;

		return 0;
	}


	int TimerQueue::GetNextTimeout()
	{
		if (!m_timerQueue.Empty())
		{
			const TimerSharedPtr& timer = m_timerQueue.Front();
			if (!timer)
				return 0;

			int timeout = static_cast<int>(timer->NextRunTime() - GetCurrentMSec());
			
			return timeout > 0 ? timeout : 0;
		}

		return -1;
	}


	void TimerQueue::Clear()
	{
		while (!m_timerQueue.Empty())
		{
			const TimerSharedPtr& timer = m_timerQueue.Front();
			m_timerQueue.Pop();

			if (!timer)
				continue;

			timer->CancelEvent();
		}
	}


	timer_id TimerQueue::CreateTimerID()
	{
		LockGuard lock(s_mutex);

		if (s_curTimers >= s_ids.size() * BYTE2BIT)
			s_ids.emplace_back(0);

		uint32 max = static_cast<uint32>(s_ids.size());
		uint32 i = 0;

		while(i < max)
		{
			byte& idBytes = s_ids[i++];

			byte bit = 0;
			while (bit < BYTE2BIT)
			{
				byte bitPos = bit++;
				if (!GetBit(idBytes, bitPos))
				{
					SetBit(idBytes, bitPos);
					return (i - 1) * BYTE2BIT + bit;
				}
			}
		}

		return 0;
	}


	void TimerQueue::ReleaseTimerID(timer_id id)
	{
		if (0 == id)
			return;

		int pos = id / BYTE2BIT;
		int bit = id % BYTE2BIT;

		LockGuard lock(s_mutex);

		if (pos >= s_ids.size())
			return;

		if (0 == bit)
			ClrBit(s_ids[pos], BYTE2BIT - 1);
		else
			ClrBit(s_ids[pos], bit - 1);
	}

}